Array.prototype.include = function (ele) {
    var e = ele;
    this.forEach(function (val) {
        if (val == e) {
            return true;
        }
    }, this);
}
window.onload = function () {
    //global vars
    var map;
    var food;
    var snake;
    var timer;
    var sum = 0;
    var speed = 500;
    var level = 1;
    var game;
    // boot the game
    game = new Game();
    game.init();
    // tool function
    function getCss(el, k) {
        if (el) {
            if (el.style[k]) {
                return el.style[k];
            }
            return null;
        }
    }
    function setCss(el, k, v) {
        if (el) {
            if (!el.style || el.style.length === 0) {
                el.style = {};
            }
            el.style[k] = v;
        }
    }
    // Object Map
    function Map() {
        this.width = 800;
        this.height = 400;
        this.bgc = "#cccccc";
        this._map = null;
        var self = this;
        this.show = function () {
            self._map = document.createElement("div");
            self._map.className = "map";
            self._map.style.width = self.width + "px";
            self._map.style.height = self.height + "px";
            self._map.style.position = "absolute";
            self._map.style.backgroundColor = self.bgc;
            self._map.style.border = "solid 2px black";
            document.getElementsByTagName("body")[0].appendChild(self._map);
        };
        this.outOfScope = function (dom) {
            if (parseInt(getCss(dom, "left")) >= self.width || parseInt(getCss(dom, "top")) >= self.height || parseInt(getCss(dom, "top")) <= 0 || parseInt(getCss(dom, "left")) <= 0) {
                return true;
            }
        };
    }
    // Object Food
    function Food() {
        this.width = 20;
        this.height = 20;
        this.bgc = "#00ff00";
        this._food = null;
        this.x = 0;
        this.y = 0;
        var self = this;
        this.show = function () {
            if (self._food === null) {
                self._food = document.createElement("div");
                self._food.className = "food";
                self._food.style.width = self.width + "px";
                self._food.style.height = self.height + "px";
                self._food.style.position = "absolute";
                self._food.style.backgroundColor = self.bgc;
                map._map.appendChild(self._food);
            }
            var contentArr = [];
            for (var i = 0; i < snake.content.length; i++) {
                var t = snake.content[i].slice(0, 2);
                contentArr.push(t.toString());
            }
            var foodArr;
            do {
                self.x = Math.floor(Math.random() * 40);
                self.y = Math.floor(Math.random() * 20);
                foodArr = [self.x, self.y].toString();
            } while (contentArr.include(foodArr));
            self._food.style.left = self.x * self.width + "px";
            self._food.style.top = self.y * self.height + "px";
        };
    }
    // Object Snake
    function Snake() {
        this.width = 20;
        this.height = 20;
        this.position = "absolute";
        this.direction = "";
        this.content = [[3, 2, "red", null], [2, 2, "blue", null], [1, 2, "blue", null]];
        var self = this;
        var len = self.content.length;
        this.setDirect = function (code) {
            switch (code) {
                case 37:
                    self.direction = "left";
                    break;
                case 38:
                    self.direction = "up";
                    break;
                case 39:
                    self.direction = "right";
                    break;
                case 40:
                    self.direction = "down";
                    break;
            }
        };
        this.show = function () {
            for (var i = 0; i < len; i++) {
                if (self.content[i][3] === null) {
                    self.content[i][3] = document.createElement("div");
                    self.content[i][3].style.width = self.width + "px";
                    self.content[i][3].style.height = self.height + "px";
                    self.content[i][3].style.position = "absolute";
                    self.content[i][3].style.backgroundColor = self.content[i][2];
                    map._map.appendChild(self.content[i][3]);
                }
                self.content[i][3].style.left = self.content[i][0] * self.width + 'px';
                self.content[i][3].style.top = self.content[i][1] * self.height + 'px';
            }
        };
        this.bodyChase = function () {
            for (var i = len - 1; i > 0; i--) {
                self.content[i][0] = self.content[i - 1][0];
                self.content[i][1] = self.content[i - 1][1];
            }
        };
        this.move = function () {
            switch (self.direction) {
                case "left":
                    self.bodyChase();
                    self.content[0][0]--;
                    break;
                case "up":
                    self.bodyChase();
                    self.content[0][1]--;
                    break;
                case "right":
                    self.bodyChase();
                    self.content[0][0]++;
                    break;
                case "down":
                    self.bodyChase();
                    self.content[0][1]++;
                    break;
                default:
                    break;
            }
            //refresh the dom of snake
            self.show();
            if (self.content[0][0] == food.x && self.content[0][1] == food.y) {
                var x = self.content[len - 1][0], y = self.content[len - 1][1];
                if (game.countPoints() === true) {
                    //append one div
                    self.content.push([x, y, "blue", null]);
                    food.show();
                }
            }
            //check if out of map scope
            for (var i = 0; i < len; i++) {
                if (map.outOfScope(self.content[i][3])) {
                    alert("Oops! Out of bound! Try again!");
                    window.location.reload();
                }
            }
            if (self.eatSelf() === true) {
                window.alert("Oops! Ate itself! Try again!");
                window.location.reload();
            }
        };
        this.eatSelf = function () {
            for (var i = 1; i < len; i++) {
                if (self.content[0][0] == self.content[i][0] && self.content[0][1] == self.content[i][1]) {
                    return true;
                }
            }
        }
    }
    // Object Game
    function Game() {
        this.init = function () {
            map = new Map(); map.show();
            snake = new Snake(); snake.show();
            food = new Food(); food.show();
            timer = window.setInterval(snake.move, (100000 / speed));
            alert("Level: " + level + " --> Speed: " + speed);
            document.onkeydown = function (ev) {
                var e = ev || event || window.event;
                var keyCode = e.keyCode || e.which || e.charCode;
                snake.setDirect(keyCode);
            };
        };
        this.countPoints = function () {
            sum++;
            if (sum >= 8) {//1->10
                sum = 0;
                document.title = "";
                speed += 200;
                if (speed >= 3000) {
                    alert("Congratulation! You Win!!!");
                    window.location.reload();
                    return;
                } else {
                    alert("You have passed level: " + level);
                    this.clearMap();
                    level++;
                    this.init();
                    document.title = "Level:" + level + " --> Points: " + sum;
                    return false;
                }
            } else {
                //contiue this level
                document.title = "Level:" + level + " --> Points: " + sum;
                return true;
            }
        };
        this.clearMap = function () {
            document.body.innerHTML = null;
            snake = null;
            map = null;
            window.clearInterval(timer);
            timer = null;
            food = null;
            sum = 0;
        };
    }

};